// Sock.cpp: implementation of the CSock class.
//
//////////////////////////////////////////////////////////////////////

#include "Sock.h"
#include <iostream>


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSock::CSock()
{
	m_Sock = -1;
	m_nType = 0;
	memset( &m_Addr, 0, sizeof(sockaddr_in) );

}

CSock::~CSock()
{



}
//----------------------------------------------------------------------------//


int CSock::Init( int nType )
{
	if( TCP == nType )
	{
		m_Sock = socket( PF_INET, SOCK_STREAM, 0 );
		if( 0 > m_Sock)
			return -1;
	}
	else if( UDP == nType )
	{
		m_Sock = socket( PF_INET, SOCK_DGRAM, 0 );
		if( 0 > m_Sock)
			return -1;
	}
	else
	{
		m_Sock = socket( PF_INET, SOCK_STREAM, 0 );
		if( 0 > m_Sock)
			return -1;
	}

	m_nType = nType;

	return 0;
}


int CSock::Connect( char* szIP, size_t nPort )
{
	if( (0 == szIP) || 0 == nPort ) 
		return -1;

	m_Addr.sin_family = AF_INET;
	m_Addr.sin_addr.s_addr = inet_addr( szIP );	
	m_Addr.sin_port = htons(nPort);
	
	int iResult = connect( m_Sock, (const sockaddr*)&m_Addr, sizeof(m_Addr) );
	if( 0 > iResult )
		return Close();

	return iResult;
}

int CSock::Close()
{

#ifdef WIN32
	int a = closesocket( m_Sock );
//	WSACleanup();
#else
	close( m_Sock );
#endif

	return -1;
}


int CSock::Bind( size_t nPort, char* szIP )
{
	if( (0 == nPort) )
		return -1;
		
	m_Addr.sin_family = AF_INET;
	m_Addr.sin_addr.s_addr = szIP == 0 ? htonl( INADDR_ANY ) : inet_addr( szIP );
	m_Addr.sin_port = htons( nPort );

	int iResult =  bind( m_Sock, (const struct sockaddr*)&m_Addr, sizeof(m_Addr) );
	if( 0 > iResult )
		return Close();
	
	return 0;
}

int CSock::Listen( size_t nBackLog )
{
	
	if( 0 == nBackLog )
		nBackLog = DEF_BACKLOG;

	int iResult = listen( m_Sock, nBackLog );
	if( 0 > iResult )
		return Close();

	return 0;
}

int CSock::Accept( CSock& PeerSock )
{
	struct sockaddr_in peer_addr;
	memset( &peer_addr, 0, sizeof(sockaddr_in) );

	socklen_t nSize = sizeof(peer_addr);
	SOCKET peer = accept( m_Sock, (sockaddr*)&peer_addr, &nSize );
	
	PeerSock.SetSocket( peer );
	PeerSock.SetAddr( &peer_addr );

	
	
	return 0;
}

int CSock::SetSockOpt( int nLevel, int nOptName, void* pOptVal, int nOptValLen )
{	

#ifdef WIN32
	int iResult = setsockopt( m_Sock, nLevel, nOptName, (const char*)pOptVal, nOptValLen );
#else
	int iResult = setsockopt( m_Sock, nLevel, nOptName, pOptVal, nOptValLen );
#endif

	return iResult;
}


int CSock::GetSockOpt( int nLevel, int nOptName, void* pOptVal, socklen_t* pnOptValLen )
{
#ifdef WIN32
	int iResult = getsockopt( m_Sock, nLevel, nOptName, (char*)pOptVal, pnOptValLen );
#else
	int iResult = getsockopt( m_Sock, nLevel, nOptName, pOptVal, pnOptValLen );
#endif

	return iResult;
}

int CSock::SetReuseAddr( bool isEnable )
{	
	int nOpt = isEnable	? 1 : 0;
	int iResult = SetSockOpt( SOL_SOCKET, SO_REUSEADDR, &nOpt, sizeof(nOpt) );

	return iResult;
}

int CSock::SetLinger( bool isEnable, int nWaitTime )
{	
	LINGER linger;
	linger.l_onoff = isEnable ? 1 : 0;
	linger.l_linger = nWaitTime <= 0 ? 0 : nWaitTime;

	int iResult = SetSockOpt( SOL_SOCKET, SO_LINGER, &linger, sizeof(LINGER) );

	return iResult;
}

int CSock::Send( char* szMsg, size_t nLen )
{
	int nSize = send( m_Sock, szMsg, nLen, 0 );
	return nSize;
}

int CSock::Recv( char* szMsg, size_t nLen )
{	
	socklen_t nSize = recv( m_Sock, szMsg, nLen, 0 );
	return nSize;
}

int CSock::Send_udp( CSock& PeerSock, char* szMsg, size_t nLen, int nFlag )
{
	socklen_t nClientAddrSize = sizeof(*PeerSock.GetAddr());
	int nSize = sendto( m_Sock, szMsg, nLen, nFlag, (struct sockaddr*)PeerSock.GetAddr(), nClientAddrSize );

	return nSize;
}

int CSock::Recv_udp( CSock& PeerSock, char* szMsg, size_t nLen, int nFlag )
{
	socklen_t nClientAddrSize = sizeof(*PeerSock.GetAddr());
	int nSize = recvfrom( m_Sock, szMsg, nLen, nFlag, (struct sockaddr*)PeerSock.GetAddr(), &nClientAddrSize );

	return nSize;
}	
